package com.share.netdisk.file.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.share.constant.Result;
import com.share.constant.StatusCode;
import com.share.holder.ContextHolder;
import com.share.netdisk.file.dao.FileDao;
import com.share.netdisk.file.pojo.File;
import com.share.netdisk.file.pojo.UserFile;
import com.share.netdisk.file.service.FileService;
import com.share.netdisk.reclaim.dao.ReclaimDao;
import com.share.netdisk.reclaim.model.Reclaim;
import lombok.extern.slf4j.Slf4j;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
@Slf4j
public class FileServiceImpl extends ServiceImpl<FileDao, File> implements FileService {

    @Value("${hdfs.uri}")
    private String hdfsUri;

    @Value("${hdfs.blocksize}")
    private String hdfsBlocksize;

    @Value("${hdfs.user}")
    private String hdfsUser;

    private final Configuration conf = new Configuration();


    @Autowired
    private FileDao fileDao;

    @Autowired
    private RedisTemplate redisTemplate;

    private FileSystem fs;

    @Autowired
   private ReclaimDao reclaimDao;

    @PostConstruct
    public void init() throws URISyntaxException, IOException, InterruptedException {
        log.info("初始化 FileSystem中...");

        // 使用 @Value 注入的属性设置 Configuration
        conf.set("fs.defaultFS", hdfsUri);
        conf.set("dfs.blocksize", hdfsBlocksize);

        fs = FileSystem.get(new URI(hdfsUri), conf, hdfsUser);
        log.info("完成FileSystem初始化");
    }

    @PreDestroy
    public void cleanup() {
        if (fs != null) {
            try {
                fs.close();
                log.info("FileSystem关闭");
            } catch (IOException e) {
                log.error("未能关闭FileSystem", e);
            }
        }
    }

    //文件上传
    @Override
    public Result add(MultipartFile file, Long parentId) {
        // 获取用户信息
        Long userId = getUserInfo();
        if (userId == null) {
            return Result.fail(StatusCode.USER_INFO_ERROR);
        }

        // 验证文件名
        String fileName = validateFileName(file);
        if (fileName == null) {
            return Result.fail(StatusCode.FILENAME_IS_BLANK);
        }

        // 构建HDFS目标路径
        //如果parentId为-1，则默认为根目录
        String path="";
        if(parentId==0){
            path="/user"+userId+"/home/";
        }else{
            path = getParentPathFromCacheOrDb(userId, parentId);
        }
        if (path == null || !path.endsWith("/")) {
            return Result.fail(StatusCode.FILE_PATH_ERROR);
        }
        log.info("目标路径: {}", path);
        Path dstPath = new Path(path + fileName);
        log.info("目标路径后: {}", dstPath);

        // 检查文件是否已存在
        if (isFileExistsInDb(userId, parentId, dstPath.toString())) {
            return Result.fail(StatusCode.FILE_EXIST);
        }

        // 将文件写入HDFS，并保存文件信息到数据库中
        try {
            writeToFileSystemAndSaveToDb(file, dstPath, userId, parentId);
            log.info("文件上传成功: {}", fileName);
            return Result.ok("文件上传成功");
        } catch (IOException e) {
            log.error("文件上传失败: {}", fileName, e);
            return Result.fail(StatusCode.FILE_UPLOAD_FAIL);
        }
    }

    //文件下载
    @Override
    public ResponseEntity<byte[]> download(Long fileId, HttpServletResponse response) {
        Long userId = getUserInfo();
        if (userId == null || fileId == null) {
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
        }

        String filePath = getPathFromCacheOrDb(userId, fileId);
        if (filePath == null) {
            return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
        }

        Path src = new Path(filePath); // 使用 Paths.get 而不是 new Path
        log.info("文件路径: {}", filePath);

        try {
            FileStatus fileStatus = fs.getFileStatus(src);
            boolean isDirectory = fileStatus.isDirectory();

            byte[] fileBytes;
            String fileName;

            if (isDirectory) {
                fileName = src.getName() + ".zip";
                fileBytes = zipDirectory(fs, src);
                log.info("正在下载目录：{}", fileName);
            } else {
                fileName = src.getName().toString();
                try (FSDataInputStream inputStream = fs.open(src)) {
                    fileBytes = FileCopyUtils.copyToByteArray(inputStream);
                }
                log.info("正在下载文件：{}", fileName);
            }

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            // 设置 Content-Disposition 时考虑文件名编码问题
            headers.setContentDispositionFormData("attachment", fileName);

            return new ResponseEntity<>(fileBytes, headers, HttpStatus.OK);

        } catch (IOException e) {
            log.error("文件下载失败: {}", src.toString(), e);
            return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    private byte[] zipDirectory(FileSystem fs, Path dirPath) throws IOException {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ZipOutputStream zos = new ZipOutputStream(baos)) {

            listFilesForFolder(fs, dirPath, "", zos);
            zos.finish();
            zos.close(); // 明确关闭 ZipOutputStream

            return baos.toByteArray();
        }
    }

    private void listFilesForFolder(FileSystem fs, final Path folder, String parent, ZipOutputStream zos) throws IOException {
        FileStatus[] statuses = fs.listStatus(folder);
        if (statuses == null || statuses.length == 0) {
            // 如果目录为空，创建一个空条目
            ZipEntry emptyDirEntry = new ZipEntry(parent + "/");
            zos.putNextEntry(emptyDirEntry);
            zos.closeEntry();
            return;
        }

        for (FileStatus status : statuses) {
            Path path = status.getPath();
            String entryName = parent + path.getName();

            if (status.isDirectory()) {
                // 添加空目录条目
                ZipEntry dirEntry = new ZipEntry(entryName + "/");
                zos.putNextEntry(dirEntry);
                zos.closeEntry();
                listFilesForFolder(fs, path, entryName + "/", zos);
            } else {
                try (FSDataInputStream inputStream = fs.open(path)) {
                    ZipEntry zipEntry = new ZipEntry(entryName);
                    zos.putNextEntry(zipEntry);
                    byte[] buffer = new byte[8192];
                    int length;
                    while ((length = inputStream.read(buffer)) > 0) {
                        zos.write(buffer, 0, length);
                    }
                    zos.closeEntry();
                } catch (IOException e) {
                    log.error("Error processing file: {}", path, e);
                    throw e; // 重新抛出异常以确保外部处理
                }
            }
        }
    }

    //文件删除,修改文件状态
    @Override
    public Result removeFileById(Long fileid) {
        //1.获取用户id
        Long userId = getUserInfo();
        if (userId == null || fileid == null) {
            return Result.fail(StatusCode.USER_INFO_ERROR);
        }
        //并且将文件的hdfs的文件路径添加到回收站表
        Reclaim reclaim = new Reclaim();
        //将long转化为int对userId
        reclaim.setHomeFileId(userId.intValue());
        reclaim.setFileId(fileid.intValue());
        reclaim.setCreateTime(new Date());
        reclaim.setUpdateTime(new Date());
        reclaim.setReclaimStatus(0);
        int insert = reclaimDao.insert(reclaim);
        //2.简历修改条件为回收站状态reclaim_status=0和file_status=0
        int i = fileDao.updateStatus(userId, fileid);

        if (i > 0&& insert > 0) {
            return Result.ok("文件删除成功");
        }
        return Result.fail(StatusCode.FILE_DELETE_FAIL);

    }

    @Override
    public Result fileList(Long fileId, Long parentId, int pageNum, int pageSize) {
        // 1. 先判断parentId是否为空，为空则返回根目录
        if (parentId == null || parentId == 0L) {
            parentId = 0L; // 0表示根目录
        }

        // 2. 获取用户id
        Long userId = getUserInfo();
        if (userId == null) {
            return Result.fail(StatusCode.USER_INFO_ERROR);
        }

        // 分页查询
        IPage<File> page;
        if (pageNum <= 0 || pageSize <= 0) {
            page = new Page<>(1, 10); // 默认分页参数
        } else {
            page = new Page<>(pageNum, pageSize);
        }

        QueryWrapper<File> queryWrapper = new QueryWrapper<>();
        if (parentId == 0 && fileId == 0) {
            parentId = 0L;
            queryWrapper.eq("home_file_id", userId).eq("parent_id", parentId).eq("file_status",1).eq("reclaim_status",1);
        } else {
            queryWrapper.eq("home_file_id", userId).eq("parent_id", fileId).eq("file_status",1).eq("reclaim_status",1);
        }

        page = fileDao.selectPage(page, queryWrapper);

        if (page.getRecords().isEmpty()) {
            System.out.println("暂时没有搜索到你的文件");
            return Result.ok("暂时没有搜索到你的文件");
        } else {
            System.out.println(page.getRecords());
        }

        return Result.ok(page);
    }

    //文件移动
    @Override
    public Result moveFile(Long srcFileId, Long dstFileId) {
        //1.获取用户id
        Long userId = getUserInfo();
        if (userId == null || srcFileId == null || dstFileId == null) {
            return Result.fail(StatusCode.USER_INFO_ERROR);
        }
        String srcPath = getPathFromCacheOrDb(userId, srcFileId);
        String dstPath = getPathFromCacheOrDb(userId, dstFileId);
        //获取srcPath的文件名
        String fileName = srcPath.substring(srcPath.lastIndexOf("/") + 1);
        if (srcPath == null || dstPath == null) {
            return Result.fail(StatusCode.FILE_PATH_ERROR);
        }
        try {
            //根据fileName判断文件类型,目标文件只能是文件夹
            if (!dstPath.endsWith("/")) {
                //目标文件不是文件夹，返回错误
                return Result.fail(StatusCode.FILE_COPY_FAIL);
            }
            if (srcPath.endsWith("/")) {
                //源文件是文件夹，此时文件名是文件夹名，此时需要拼接文件名
                String dbFileName = srcPath.substring(srcPath.lastIndexOf("/") - 1);
                fileName = dbFileName.substring(dbFileName.lastIndexOf("/") + 1);

            }
            //3.移动文件
            fs.rename(new Path(srcPath), new Path(dstPath));
            //数据库中修改时需要dstPath+文件名
            String dbPath = dstPath + fileName;
            //4.修改文件路径
            fileDao.updateParentPath(userId, srcFileId, dstFileId, dbPath);
            //5.删除缓存
            String key = buildRedisKey(userId, srcFileId);
            redisTemplate.delete(key);
            //重新生成缓存
            redisTemplate.opsForValue().set(key, dbPath, 30, TimeUnit.MINUTES);
            return Result.ok("文件移动成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    //文件复制
    @Override
    public Result copyFile(Long srcFileId, Long dstFileId) {
        //1.获取用户id
        Long userId = getUserInfo();
        if (userId == null || srcFileId == null || dstFileId == null) {
            return Result.fail(StatusCode.USER_INFO_ERROR);
        }
        //2.获取文件路径
        String srcPath = getPathFromCacheOrDb(userId, srcFileId);
        String dstPath = getPathFromCacheOrDb(userId, dstFileId);
        String fileName = srcPath.substring(srcPath.lastIndexOf("/") + 1);
        log.warn("srcPath: {}, dstPath: {},filename:{}", srcPath, dstPath, fileName);
        if (srcPath == null || dstPath == null) {
            return Result.fail(StatusCode.FILE_PATH_ERROR);
        }
        try {
            //根据fileName判断文件类型,目标文件只能是文件夹
            if (!dstPath.endsWith("/")) {
                //目标文件不是文件夹，返回错误
                return Result.fail(StatusCode.FILE_COPY_FAIL);
            }
            if (srcPath.endsWith("/")) {
                //源文件是文件夹，此时文件名是文件夹名，此时需要拼接文件名
                String dbFileName = srcPath.substring(srcPath.lastIndexOf("/") - 1);
                fileName = dbFileName.substring(dbFileName.lastIndexOf("/") + 1);

            }

            //3.复制文件
            FileUtil.copy(fs, new Path(srcPath), fs, new Path(dstPath), false, true, conf);
            //4.先去数据库中查询返回srcFileId对应的文件信息
            File userFile = fileDao.selectFileEntity(userId, srcFileId);
            File newUserFile = new File();
            newUserFile.setUserId(userId);
            newUserFile.setParentId(dstFileId);
            newUserFile.setHomeFileId(userFile.getHomeFileId());
            newUserFile.setFileName(fileName);
            newUserFile.setFileUrl(dstPath + fileName);
            newUserFile.setTypeId(userFile.getTypeId());
            newUserFile.setFileSize(userFile.getFileSize());
            newUserFile.setFileStatus(userFile.getFileStatus());
            newUserFile.setReclaimStatus(userFile.getReclaimStatus());
            newUserFile.setShareStatus(userFile.getShareStatus());


            int insert = fileDao.insert(newUserFile);
            if (insert > 0) {
                //插入成功删除Redis缓存
                String key = buildRedisKey(userId, srcFileId);
                redisTemplate.delete(key);
                redisTemplate.opsForValue().set(key, dstPath + fileName, 30, TimeUnit.MINUTES);
                return Result.ok("文件复制成功");
            }
            return Result.fail(StatusCode.FILE_COPY_FAIL);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //文件重命名
    @Override
    public Result renameFile(Long fileId, String newName) {
        //1.获取用户id
        Long userId = getUserInfo();
        if (userId == null || fileId == null) {
            return Result.fail(StatusCode.USER_INFO_ERROR);
        }
        //2.获取文件路径
        String filePath = getPathFromCacheOrDb(userId, fileId);
        if (filePath == null) {
            return Result.fail(StatusCode.FILE_PATH_ERROR);
        }
        String newFilePath = "";
        //如果filePath是文件，
        if (filePath.endsWith("/")) {
            //截取倒数第二个”/“之后的字符串，然后拼接上newName
            String first = filePath.substring(0, filePath.lastIndexOf("/"));
            String updatePath = first + "/";
            newFilePath = first.substring(0, first.lastIndexOf("/")) + "/" + newName + "/";
            //从数据库中查找文件路径以first这个字符串开头的文件，然后统一将文件前缀改为newFilePath
            List<File> files = fileDao.selectFileByPath(userId, first);
            for (File file : files) {
                //拿到文件路径
                String filePath1 = file.getFileUrl();
                //将文件路径前缀改为newFilePath
                String dbNewFilePath = filePath1.replace(updatePath, newFilePath);
                fileDao.updateFileUrl(userId, file.getFileId(), dbNewFilePath);
            }
        } else {
            newFilePath = filePath.substring(0, filePath.lastIndexOf("/") + 1) + newName;
        }

        try {
            fs.rename(new Path(filePath), new Path(newFilePath));
            //3.修改数据库文件路径
            int i = fileDao.updateFileUrl(userId, fileId, newFilePath);
            if (i <= 0) {
                return Result.fail(StatusCode.FILE_RENAME_FAIL);
            }
            //4.删除缓存
            String key = buildRedisKey(userId, fileId);
            redisTemplate.delete(key);
            //5.重新生成缓存
            redisTemplate.opsForValue().set(key, newFilePath, 30, TimeUnit.MINUTES);
            return Result.ok("文件重命名成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //创建文件
    @Override
    public Result createFile(String fileName, Long parentId) {
        Long userId = getUserInfo();
        if (userId == null) {
            return Result.fail(StatusCode.USER_INFO_ERROR);
        }
        String parentPath = "";
        if (parentId == null || parentId == 0) {
            parentId = 0L;//默认创建在根目录下
            parentPath = "/user" + userId + "/home/";
        }
        if (parentId != 0) {
            //根据用户名和parentId获取父级目录路径
            parentPath = getParentPathFromCacheOrDb(userId, parentId);
        }
        //根据文件名后缀确定文件类型
        Long fileType = determineFileType(fileName);
        String newFilePath = "";
        //只要是文件夹就加“/”
        if (fileType == 1) {
            newFilePath = parentPath + fileName + "/";
        } else {
            newFilePath = parentPath + fileName;
        }

        if (isFileExistsInDb(userId, parentId, newFilePath)) {
            return Result.fail(StatusCode.FILE_EXIST);
        }
        //将信息插入数据库
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedDate = now.format(formatter);
        File userFile = new File(userId, parentId, userId, fileName, newFilePath, fileType, 0L,formattedDate );
        int insert = fileDao.insertFile(userFile);
        //插入成功返回文件id
        if (insert > 0) {
            Long fileId = userFile.getFileId();
            redisTemplate.opsForValue().set(buildRedisKey(userId, fileId), newFilePath, 30, TimeUnit.MINUTES);
            //创建文件到hdfs上
            Path newdir = new Path(newFilePath);
            if (fileType == 1) {
                boolean flag = false;
                try {
                    flag = fs.mkdirs(newdir);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                if (flag) {
                    return Result.ok("文件目录创建成功", fileId);
                }
            }
            //创建文件
            try {
                FSDataOutputStream out = fs.create(newdir);
                out.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return Result.ok("文件创建成功", fileId);
        }
        return Result.fail(StatusCode.FILE_CREATE_FAIL);
    }

    //文件搜索
    @Override
    public Result searchFile(String fileName, Long parentId,int pageNum,int pageSize) {
        log.warn("进入");
        Long userId = getUserInfo();
        if (userId == null || (parentId == null && fileName == null)) {
            return Result.fail(StatusCode.USER_INFO_ERROR);
        }
        String parentPath = "";
        if (parentId == null || parentId == 0) {
            parentPath = "/user" + userId + "/home/";
        } else {
            parentPath = getParentPathFromCacheOrDb(userId, parentId);
        }
        IPage<File> page;

        if(pageNum<=0 || pageSize<=0){
            page = new Page<>(1, 10);
        }else{
            page = new Page<>(pageNum, pageSize);
        }

        try {
            Pattern pattern = fileName == null ? null : Pattern.compile(".*" + Pattern.quote(fileName) + ".*");
            List<String> filePaths = new ArrayList<>();
            searchFilesRecursively(fs, new Path(parentPath), pattern, userId, filePaths);
            QueryWrapper<File> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("file_url", filePaths).eq("home_file_id", userId).eq("file_status",1).eq("reclaim_status",1);
            // 批量查询文件信息
            page=fileDao.selectPage(page,queryWrapper);
            if(page.getRecords().isEmpty()){
                log.info("没有找到文件");
                return Result.ok("");
            }
            return Result.ok(page);
        } catch (IOException e) {
            e.printStackTrace();
            return Result.fail(StatusCode.INTERNAL_ERROR);
        }
    }

    private void searchFilesRecursively(FileSystem fs, Path path, Pattern pattern, Long userId, List<String> filePaths) throws IOException {
        FileStatus[] statuses = fs.listStatus(path);
        if (statuses != null) {
            for (FileStatus status : statuses) {
                Path filePath = status.getPath();
                String fileName = filePath.getName();

                // 如果有正则表达式并且文件名匹配，或者没有正则表达式（即匹配所有文件）
                if (pattern == null || pattern.matcher(fileName).matches()) {
                    System.out.println("Found: " + filePath);
                    //hdfs://192.168.142.111:9000/user2/home/C/A.txt
                    //截取9000后面的路径
                    String filePathStr = filePath.toString().substring(hdfsUri.length());
                    //判断是否有后缀，并且文件类型为1
                    if (!fileName.contains(".") || determineFileType(fileName) == 1) {
                        filePathStr = filePathStr + "/";
                    }
                    log.warn("filePathStr: " + filePathStr);
                    filePaths.add(filePathStr);
                }

                // 如果是目录，则递归搜索子目录
                if (status.isDirectory()) {
                    searchFilesRecursively(fs, filePath, pattern, userId, filePaths);
                }
            }
        }
    }


    // 判断用户信息
    private Long getUserInfo() {
        return Optional.ofNullable(ContextHolder.get())
                .orElse(null);
    }

    // 验证文件名
    private String validateFileName(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        return StringUtils.isNotBlank(fileName) ? fileName : null;
    }

    // 从缓存或数据库中获取父文件路径
    private String getParentPathFromCacheOrDb(Long userId, Long parentId) {
        String key = buildRedisKey(userId, parentId);
        return Optional.ofNullable((String) redisTemplate.opsForValue().get(key))
                .orElseGet(() -> {
                    String selectPath = fileDao.selectParentFile(userId, parentId);
                    if (selectPath != null && selectPath.endsWith("/")) {
                        redisTemplate.opsForValue().set(key, selectPath, 1, TimeUnit.DAYS);
                    }
                    return selectPath;
                });
    }

    // 从缓存或数据库中获取文件路径
    private String getPathFromCacheOrDb(Long userId, Long fileId) {
        String key = buildRedisKey(userId, fileId);
        return Optional.ofNullable((String) redisTemplate.opsForValue().get(key))
                .orElseGet(() -> {
                    String selectPath = fileDao.selectFile(userId, fileId);
                    if (selectPath != null) {
                        redisTemplate.opsForValue().set(key, selectPath, 1, TimeUnit.DAYS);
                    }
                    return selectPath;
                });
    }

    //判断文件是否已存在
    private boolean isFileExistsInDb(Long userId, Long parentId, String fileUrl) {
        LambdaQueryWrapper<File> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(File::getUserId, userId)
                .eq(File::getParentId, parentId)
                .eq(File::getFileUrl, fileUrl);
        return fileDao.selectOne(queryWrapper) != null;
    }

    // 将文件写入HDFS，并保存文件信息到数据库中
    private void writeToFileSystemAndSaveToDb(MultipartFile file, Path dstPath, Long userId, Long parentId) throws IOException {
        try (InputStream inputStream = file.getInputStream();
             FSDataOutputStream outputStream = fs.create(dstPath)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, bytesRead);
            }
            if(parentId==-1){
                parentId=0L;
            }
            log.info("文件写入HDFS成功");
            File fileEntity = createFileEntity(file, dstPath, userId, parentId);
            if (fileDao.insert(fileEntity) <= 0) {
                throw new RuntimeException("文件插入数据库失败");
            }
        }
    }

    // 创建文件实体
    private File createFileEntity(MultipartFile file, Path dstPath, Long userId, Long parentId) {
        File fileEntity = new File();
        fileEntity.setUserId(userId);
        fileEntity.setParentId(parentId);
        fileEntity.setFileName(file.getOriginalFilename());
        fileEntity.setFileUrl(dstPath.toString());
        fileEntity.setFileSize(file.getSize());
        fileEntity.setHomeFileId(userId);
        fileEntity.setTypeId(determineFileType(file.getOriginalFilename())); // 根据文件后缀判断文件类型
        fileEntity.setUpdateTime(String.valueOf(LocalDateTime.now()));
        return fileEntity;
    }

    // 构建Redis键
    private String buildRedisKey(Long userId, Long parentId) {
        return String.format("userId:%d:fileId:%d", userId, parentId);
    }

    // 根据文件后缀判断文件类型
    private Long determineFileType(String fileName) {
        // 实现根据文件后缀判断文件类型的逻辑
        //2.图片
        if (fileName.endsWith(".jpg") || fileName.endsWith(".png")) {
            return 2l;
        }
        //3.文档
        if (fileName.endsWith(".doc") || fileName.endsWith(".pdf") || fileName.endsWith(".docx") || fileName.endsWith(".txt")) {
            return 3l;
        }
        //4.音频
        if (fileName.endsWith(".mp3")) {
            return 4l;
        }
        //5.视频
        if (fileName.endsWith(".mp4")) {
            return 5l;
        }
        //6.压缩包
        if (fileName.endsWith(".zip") || fileName.endsWith(".rar") || fileName.endsWith(".7z")) {
            return 6l;
        }
        //1.文件夹
        return 1l; // 默认类型,表示文件夹
    }

    // 插入家目录文件到数据库
    @Override
    public boolean insertHomeFile(UserFile userFile) {
        if (userFile == null) {
            return false;
        }
        return fileDao.insertHomeFile(userFile) > 0;
    }
}
